#include "EPollPoller.hpp"
#include "Logger.hpp"
#include "Channel.hpp"

#include <errno.h>
#include <unistd.h>
#include <memory.h>


const int kNew = -1; //channel未添加到poller中 --channel的成员index_=-1
const int kAdded = 1; //channel已添加到poller中
const int kDeleted = 2; //channel从poller中删除

EPollPoller::EPollPoller(EventLoop *loop)
    :Poller(loop)
    ,epollfd_(::epoll_create1(EPOLL_CLOEXEC)) //防止文件描述符子进程中泄漏
    ,events_(kInitEventListSize)
{
    if(epollfd_<0)
    {
        LOG_FATAL("epoll_create error:%d \n",errno);
    }
}

EPollPoller::~EPollPoller()
{
    ::close(epollfd_);
}

Timestamp EPollPoller::poll(int timeoutMs,ChannelList *activeChannels)
{
    // 实际上应该用LOG_DEBUG输出日志更为合适
    LOG_INFO("func=%s => fd total count:%lu\n",__FUNCTION__,channels_.size());

    int numEvents=::epoll_wait(epollfd_,&*events_.begin(),static_cast<int>(events_.size()),timeoutMs);
    int saveErrno=errno;
    Timestamp now(Timestamp::now());

    if(numEvents>0)
    {
        LOG_INFO("%d events happened \n",numEvents);
        fillActiveChannels(numEvents,activeChannels);
        if(numEvents==events_.size())
        {
            events_.resize(events_.size()*2);
        }
    }
    else if(numEvents==0)
    {
        LOG_DEBUG("%s timeout! \n",__FUNCTION__);
    }
    else
    {
        if(saveErrno != EINTR)
        {
            errno =saveErrno;
            LOG_ERROR("EPollPoller::poll() err!");
        }
    }
    return now;
}

// channel--update remove => EventLoop--updateChannel removeChannel => Poller--updateChannel reomveChannel
/**
 *        EventLoop
 *  ChannelList    Poller
 *              ChannelMap(channels_) <fd,Channel*>
 */
void EPollPoller::updateChannel(Channel *channel)
{
    const int index=channel->index();
    LOG_INFO("func=%s => fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),index);
    if(index==kNew || index==kDeleted)
    {
        int fd=channel->fd();
        if(index==kNew)
        {
            channels_[fd]=channel;
        }
        update(EPOLL_CTL_ADD,channel);
        channel->set_index(kAdded);
    }
    else //channel已经在poller上注册过了
    {
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL,channel);
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD,channel);
        }
        
    }
}

void EPollPoller::removeChannel(Channel *channel)
{
    int fd=channel->fd();
    channels_.erase(fd);

    LOG_INFO("func=%s => fd=%d\n",__FUNCTION__,fd);

    int index=channel->index();
    if(index==kAdded)
    {
        update(EPOLL_CTL_DEL,channel);
    }
    channel->set_index(kNew);
}

//填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents,ChannelList *activeChannels) const
{
    for(int i=0;i<numEvents;i++)
    {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel); //EventLoop就拿到了它的poller给它返回的所有发生事件的channel列表了
    }

}

//更新channel通道 epoll_ctl add/mod/del
void EPollPoller::update(int operation,Channel *channel)
{
    epoll_event event;
    memset(&event,0,sizeof event);

    int fd=channel->fd();

    event.events=channel->events();
    event.data.fd=fd;
    event.data.ptr=channel;
    if(::epoll_ctl(epollfd_,operation,fd,&event)) //出错
    {
        if(operation==EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d\n",errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error:%d\n",errno);
        }
    }
}